#!coding:utf-8
import os
from django.db import models,connections
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from cvirt.common import constant
from cvirt.common import utils
from django.db.models.query import QuerySet

from djcelery.models import TaskMeta, IntervalSchedule, CrontabSchedule
from cvirt.manager.schedule.schedulemanage import CvirtPeriodicTaskManager

#for soft delete model init
from cvirt.manager.softdelete import SoftDeleteQuerySet, SoftDeleteManager, SoftDeleteObject


class CQuerySet(SoftDeleteQuerySet):
    def get_or_none(self, *args, **kwargs):
        try:
            return super(CQuerySet,self).get(*args,**kwargs)
        except self.model.DoesNotExist:
            return None

    def first(self,*args, **kwargs):
        first = self.filter(*args, **kwargs)[0:1]
        return first[0] if first else None

class CManager(SoftDeleteManager):
    def get_query_set(self):
        "model默认查询deleted=False的数据"
        return CQuerySet(self.model, using=self._db).filter(deleted_at__isnull=True)

    def first(self,*args, **kwargs):
        return self.get_query_set().first(*args, **kwargs)

    def get_or_none(self, *args, **kwargs):
        return self.get_query_set().get_or_none(*args, **kwargs)


class Base(SoftDeleteObject):
    objects = CManager()
    created_at = models.DateTimeField(null=True, blank=True)
    updated_at = models.DateTimeField(null=True, blank=True)
    # deleted_at = models.DateTimeField(null=True, blank=True)
    # deleted = models.BooleanField(default=False)
    # id = models.AutoField(primary_key=True)
    class Meta:
        abstract = True

    def remove(self):
        "数据库有关联，但是不需要级联删除则调用remove"
        self.deleted_at = utils.utcnow()
        self.save()

    def __getitem__(self, item):
        if hasattr(self,item):
            return getattr(self,item)

    def update(self,values,save=True):
        for k,v in values.items():
            if hasattr(self,k):
                setattr(self, k, v)
        if save: self.save()
        return self

    def save(self,force_insert=False, force_update=False, using=None,
             update_fields=None):
        # self.full_clean()
        self.updated_at = utils.utcnow()
        if not self.created_at:
            self.created_at = utils.utcnow()
        super(Base, self).save(force_insert=force_insert, force_update=force_update, using=using,update_fields=update_fields)


class Datacenter(Base):
    name = models.CharField(max_length=255)

    class Meta:
        db_table='datacenter'

# 实例和interface为一对多关系,interface和网络是一对一关系
# cluster和host，network，storage为一对多关系
# host 和 backup为一对多关系

class Cluster(Base):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=1024,null=True,blank=True)
    cpufamily = models.CharField(max_length=255,null=True,blank=True)
    datacenter = models.ForeignKey(Datacenter)
    class Meta:
        db_table = u'cluster'


class Server(Base):
    host_name = models.CharField(max_length=255)
    ip = models.IPAddressField()
    password = models.CharField(max_length=255)
    port = models.IntegerField(default=22)
    # use_sshkey = models.BooleanField()
    cpu = models.IntegerField(default=0)
    mem = models.IntegerField(default=0)
    arch = models.CharField(max_length=10)
    os = models.CharField(max_length=255)
    hypervisor = models.CharField(max_length=20)
    memshare = models.BooleanField(default=True)
    cpu_type = models.CharField(max_length=255)
    qemu_version = models.CharField(max_length=50)
    # powermanager = models.BooleanField(default=False)
    powertool = models.IntegerField(null=True,blank=True) #0-none,1-dell,2-hp, 3-iBM
    powercard_address = models.IPAddressField(null=True,blank=True)
    powercard_username = models.CharField(max_length=50, null=True,blank=True)
    powercard_password = models.CharField(max_length=50, null=True,blank=True)
    cluster = models.ForeignKey(Cluster,null=True,blank=True)
    ##########
    # work load * 100
    # TODO 这些是实时数据，不能写死到数据库，很难维护一致性 by shankangjie
    # current_workload = models.IntegerField(null=True,blank=True)
    # running_vms = models.IntegerField(null=True,blank=True)
    cpu_usage = models.IntegerField(default=0)  #schedule 定时更新
    mem_usage = models.IntegerField(default=0)

    status = models.IntegerField(default=1) #0-维护模式,1-未激活,2-已激活,3-关机

    #----------bound network config-------------------
    usedhcp = models.BooleanField(default=False)
    address = models.IPAddressField(null=True,blank=True)
    netmask = models.IPAddressField(null=True,blank=True)
    gateway = models.IPAddressField(null=True,blank=True)
    dns1 = models.IPAddressField(null=True,blank=True)
    dns2 = models.IPAddressField(null=True,blank=True)

    class Meta:
        db_table = u'server'


# class ServerInterface(Base):
#     name = models.CharField(max_length=255)
#     link_base = models.IntegerField()   #100mb, 1000mb
#     type = models.IntegerField()  #0-管理网络,1-存储网络，2-数据网络,3-数据网络（bound)
#     vlan = models.CharField(max_length=10,null=True,blank=True)   #服务器网卡对应的vlan id
#     cluster = models.ForeignKey(Cluster)  #网络规划和集群关联
#     class Meta:
#         db_table = u'server_interface'

class Setting(Base):
    name = models.CharField(max_length=255, unique=True)
    value = models.CharField(max_length=255)
    description = models.CharField(max_length=255,null=True,blank=True)

    class Meta:
        db_table = u'setting'



class Network(Base):
    # name = models.CharField(max_length=255,primary_key=True)
    name = models.CharField(max_length=255)
    # uuid = models.CharField(max_length=255)
    cidr = models.CharField(max_length=255,null=True,blank=True)
    address = models.IPAddressField(null=True,blank=True)
    netmask = models.IPAddressField(null=True,blank=True)
    dev = models.CharField(max_length=50,null=True,blank=True)
    stp = models.CharField(max_length=3,default='off')
    delay = models.IntegerField(default=0)

    rundhcp = models.BooleanField()
    dhcp_start = models.IPAddressField(null=True,blank=True)
    dhcp_end = models.IPAddressField(null=True,blank=True)
    networktype = models.IntegerField()  #0-nat,1-isolate,2-route,3-vlan

    #---------------networktype = 2 -------------------------
    bridge = models.CharField(max_length=255,null=True,blank=True)  #记录桥接网络的网桥
    # bridge_interface = models.OneToOneField(ServerInterface,null=True,blank=True)  #桥接网络对应的interface

    #---------------networktype = 2,3 -------------------------
    gateway = models.IPAddressField(null=True,blank=True)
    dns1 = models.IPAddressField(null=True,blank=True)
    dns2 = models.IPAddressField(null=True,blank=True)
    #---------------networktype = 2,3 -------------------------

    #---------------networktype = 3 -------------------------
    vlanid = models.IntegerField(null=True,blank=True)

    cast_snoop = models.BooleanField(default=True)  #for muilcast snooping

    cluster = models.ForeignKey(Cluster)

    def should_allocate_ip(self):
        return (self.networktype == 2 or self.networktype == 3) and self.rundhcp

    @property
    def libvirt_name(self):
        '''
        用于libvirt底层network的定义
        @return:
        '''
        return "%s_%s" % (self.name,self.id)

    class Meta:
        db_table = u'network'

    def remove(self):
        '''
        因为network的删除不能使用级联删除
        network删除后，删除相应的fixedip和proposal
        @return:
        '''
        for fixip in self.fixedip_set.all():
            fixip.remove()
        for p in self.proposal_set.all():
            p.remove()
        super(Network,self).remove()


class Storage(Base):
    name = models.CharField(max_length=255)

    type = models.CharField(max_length=50)  #data,iso

    # is_backup = models.BooleanField()
    # is_data = models.BooleanField()  #data,template
    # is_iso = models.BooleanField()   #iso
    # is_template = models.BooleanField()

    protocol = models.CharField(max_length=255) #nfs,iscsi,local,cifs

    mount_point = models.CharField(max_length=255)
    status = models.CharField(max_length=50,null=True,blank=True)
    host = models.CharField(max_length=50,null=True,blank=True)
    username = models.CharField(max_length=255,null=True,blank=True)
    password = models.CharField(max_length=50,null=True,blank=True)

    #cifs
    #nfs
    path = models.CharField(max_length=255,null=True,blank=True)

    #iscsi
    target = models.CharField(max_length=255,null=True,blank=True)

    cluster = models.ForeignKey(Cluster)
    used = models.IntegerField(default=0)
    totalsize = models.IntegerField(default=0)
    class Meta:
        db_table = u'storage'

    def free(self):
        return self.totalsize - self.used

    def remove(self):
        '''
        因为storage的删除不能使用级联删除
        storage删除后，删除相应的proposal
        @return:
        '''
        for p in self.proposal_set.all():
            p.remove()
        super(Storage,self).remove()

class User(Base):
    """
    this model be used for client user
    for admin user we should use django.contrib.auth.models.User
    """
    username = models.CharField(max_length=255)
    organize = models.CharField(max_length=255,null=True,blank=True)
    phone = models.BigIntegerField(null=True,blank=True)
    status = models.CharField(max_length=8,default='offline') #offline，online,deny
    password = models.CharField(max_length=255)
    last_login = models.DateTimeField(null=True)
    last_login_ip = models.IPAddressField(null=True)
    vm_used = models.CharField(max_length=255,null=True,blank=True)

    class Meta:
        db_table = u'user'

# class UserGroup(Base):pass
#
# class UserRole(Base):pass


class Alarm(Base):
    """告警任务"""
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=1024,null=True)
    host = models.CharField(max_length=255)
    ip = models.CharField(max_length=255)
    check_period = models.IntegerField() #检查周期, 0-7*24,1-时间段
    check_start = models.DateTimeField(null=True)
    check_end = models.DateTimeField(null=True)

    notify_period = models.IntegerField(null=True) #通知时间段,0-7*24,1-时间段
    notify_start = models.DateTimeField(null=True)
    notify_end = models.DateTimeField(null=True)

    notify_content = models.CharField(max_length=255)

    contacts = models.CharField(max_length=255)
    max_check_retry = models.IntegerField() #重试次数
    check_interval = models.IntegerField() #检查间隔
    retry_interval = models.IntegerField() #重试间隔
    notify_interval = models.IntegerField(null=True) #告警间隔,默认0为一次性告警
    notify_enable = models.BooleanField() #是否告警
    notifytype = models.IntegerField(default=0) #0-email,1-sms
    active = models.BooleanField()  #是否激活
    status = models.IntegerField()  #0-正常,1-警告,2-错误,3-未知
    last_check = models.DateTimeField() #上次检查时间
    next_check = models.DateTimeField() #下次检查时间
    command = models.CharField(max_length=255) #命令
    #args = models.CharField(max_length=255) #命令参数

    #notifys = relationship("Notify", backref="task")

    def __str__(self):
        return "%s" % (self.name,)

    @property
    def hashcode(self):
        return hash("%s%s" % (self.id,self.name))

    class Meta:
        db_table = u'alarm'

class Notify(Base):
     class Meta:
         db_table = u'notify'


class BackupPolicy(Base):
    name = models.CharField(max_length=255)
    backuptype = models.IntegerField()  #0-冷备份 , 1-热备份
    compress = models.BooleanField()
    compresslevel = models.IntegerField() # 0 ~ 9
    remain = models.IntegerField()  #0-所有 or 天数
    locationtype = models.IntegerField()  #0-本地 , 1-已关联存储 , 3-sftp
    localpath = models.CharField(max_length=1024,null=True,blank=True)
    storage = models.ForeignKey(Storage,null=True,blank=True)
    sftpusername = models.CharField(max_length=255,null=True,blank=True)
    sftphost = models.CharField(max_length=255,null=True,blank=True)   # TODO: should we use IpAddressField for not be consider dns?
    sftppath = models.CharField(max_length=1024,null=True,blank=True)
    sftppassword = models.CharField(max_length=255,null=True,blank=True)

    backupfrequency = models.IntegerField()  #0-每小时,  #1-每天, #2-每周, #每月
    backuptime = models.TimeField()
    weekday = models.CharField(max_length=10, null=True, blank=True)
    monthday = models.IntegerField(null=True, blank=True)

    class Meta:
        db_table = u'backup_policy'

class Template(Base):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=255,null=True,blank=True)

    format = models.CharField(max_length=255)
    size = models.BigIntegerField()
    status = models.CharField(max_length=50)
    # owner = models.CharField(max_length=50)

    os_type = models.CharField(max_length=50)

    storagehost = models.CharField(max_length=255,null=True,blank=True)   #如果镜像存储在local的存储上，storagehost字段用来识别是哪个host的local存储
    # is_64 = models.BooleanField()
    # is_desktop = models.BooleanField()

    virtualsize = models.BigIntegerField(default=0)

    storage = models.ForeignKey(Storage)
    #
    # @property
    # def arch_type(self):
    #     rt = 3
    #     if constant.isWindows(self.os_type):
    #         rt = 1
    #     elif constant.isLinux(self.os_type):
    #         rt = 2
    #     return rt

    class Meta:
        db_table = u'template'


class Snapshot(Base):

    # @property
    # def display_id(self):
    #     return SNAP_TEMPLATE % self.id

    instance = models.ForeignKey("Instance")
    uuid = models.CharField(max_length=36)

    status =  models.CharField(max_length=255, null=True, blank=True)
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=256, null=True, blank=True)

    class Meta:
        db_table = u'snapshot'


class SecurityGroup(Base):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=1024, null=True,blank=True)

    class Meta:
        db_table = u'security_group'

    #security_group_rules


class IngressRule(models.Model):
    protocol = models.CharField(max_length=10)    # "tcp", "udp", or "icmp","all"

    srcipfrom = models.IPAddressField(null=True,blank=True)#Start of range of source IP address
    srcipto = models.IPAddressField(null=True,blank=True)#End of range of source IP address

    srcportstart = models.CharField(max_length=5,null=True,blank=True)#Start of range of valid source ports
    srcportend = models.CharField(max_length=5,null=True,blank=True)#End of range of valid source ports

    dstipfrom = models.IPAddressField(null=True,blank=True)#Start of range of destination IP address
    dstipto = models.IPAddressField(null=True,blank=True)#End of range of destination IP address

    dstportstart = models.CharField(max_length=5,null=True,blank=True)#Start of range of valid destination ports
    dstportend = models.CharField(max_length=5,null=True,blank=True)#End of range of valid destination ports

    direction = models.CharField(max_length=10) # in :vm -->outside , out : outside --> vm, inout :vm <---> outside
    priority = models.CharField(max_length=5)  #优先级  1 ~ 800 , 越小优先级越高
    action = models.CharField(max_length=255)#accept , drop

    class Meta:
        abstract = True

class Instance(Base):

    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255,null=True,blank=True)
    uuid = models.CharField(max_length=255)
    # for cluster retrieving
    host = models.ForeignKey(Server)

    # image = models.ForeignKey(Image,null=True,blank=True)

    vcpu = models.IntegerField(default=1)
    memory = models.IntegerField(default=1024)

    acpi = models.BooleanField(False)
    apic = models.BooleanField(default=False)
    cpu_host_model = models.BooleanField(default=False)
    nestedvt = models.BooleanField(default=False)

    bootorder = models.CharField(max_length=255,default="hd")   #hd,cdrom

    clock = models.CharField(max_length=50,choices=(('utc','utc'),('localtime','localtime')),default='localtime')
    xml = models.TextField(null=True,blank=True)

    #使用storage的mount_point,主机上存在多个存储
    # instance_path = models.CharField(max_length=255)
    status = models.CharField(max_length=32)
    power_status = models.IntegerField()

    graphics_type = models.CharField(max_length=32,null=True,blank=True)
    os_type = models.CharField(max_length=32,null=True,blank=True)

    cpu_usage = models.IntegerField(default=0)  #schedule 定时更新,用于top5
    mem_usage = models.IntegerField(default=0)

    user = models.ForeignKey(User,null=True,blank=True)

    autostart = models.BooleanField(default=False)
    bootmenu = models.BooleanField(default=False)

    hapriority = models.IntegerField(default=0)  #0-无，1-低，2-中，3-高

    resetmode = models.BooleanField(default=False)  #是否启用还原模式

    soundcard = models.CharField(max_length=255,null=True,blank=True)  #none则表示不启用声卡

    remote_password = models.CharField(max_length=255,null=True,blank=True)

    #------------spice config--------------------
    usbredir = models.BooleanField(default=False)
    monitor = models.IntegerField(default=1)
    image_compress = models.CharField(max_length=255,default='auto_glz')
    jpeg_compress = models.CharField(max_length=255,default='always')
    streaming_mode = models.CharField(max_length=255,default='all')
    vram = models.IntegerField(default=65536) #默认64MB显存

    @property
    def graphics_port(self):
        #TODO 端口累加的方式有缺陷(只增不减)，我们需要重新讨论
        port = 5900 + self.id
        return port


    backup_policy = models.OneToOneField(BackupPolicy,null=True,blank=True)

    watchdog = models.CharField(max_length=255,null=True,blank=True)
    dogaction = models.CharField(max_length=255,null=True,blank=True)

    def __str__(self):
        return "%s" % (self.name,)

    class Meta:
        db_table = u'instances'

class VDisk(Base):
    name = models.CharField(max_length=255)
    description = models.CharField(max_length=255,blank=True,null=True)
    # user_id = models.IntegerField(blank=True,null=True)
    format = models.CharField(max_length=50)  #qcow2,raw
    cache = models.CharField(max_length=50,null=True,blank=True)

    # snapshot_id = models.IntegerField(blank=True,null=True)
    device_type = models.CharField(max_length=20,choices=[('disk','disk'),('cdrom','cdrom')])
    mountpoint = models.CharField(max_length=255,null=True,blank=True)
    size = models.IntegerField(default=0)
    max_size = models.IntegerField(default=0)

    bus = models.CharField(max_length=50,null=True,blank=True)
    iomode = models.CharField(max_length=50,null=True,blank=True)

    readonly = models.BooleanField(default=False)
    # share = models.BooleanField(default=False)

    # host = models.ForeignKey(Server)
    storage = models.ForeignKey(Storage,null=True,blank=True)
    instance = models.ForeignKey(Instance,null=True,blank=True)

    image = models.ForeignKey(Template,null=True,blank=True)
    isopath = models.CharField(max_length=1024,null=True,blank=True)


    @property
    def disk_path(self):
        if self.storage.protocol=='iscsi' and self.device_type=='disk':
            return self.iscsilun.path
        else:
            return os.path.join(self.storage.mount_point,"vdisks_%s" % self.storage.cluster.id,"%s_%s" % (self.name,self.id))

    class Meta:
        db_table = u'vdisk'

class Interface(Base):
    name = models.CharField(max_length=255)
    mac = models.CharField(max_length=255)
    model = models.CharField(choices=(('e1000','e1000'),('pcnet','pcnet'),('virtio','virtio'),
                                      ('rtl8139','rtl8139'),('ne2k_pci','ne2k_pci')),default='e1000',max_length=50)

    network = models.ForeignKey(Network,null=True,blank=True)
    instance = models.ForeignKey(Instance)
    fixedip = models.OneToOneField('FixedIp',null=True,blank=True)  #for bridge network

    securitygroups = models.ManyToManyField(SecurityGroup,null=True,blank=True)
    enable = models.BooleanField(default=False)

    class Meta:
        db_table = u'interface'

class Backup(Base):
    """
    备份执行日志
    """
    status = models.BooleanField()
    backuppolicy = models.ForeignKey(BackupPolicy)
    instance = models.ForeignKey(Instance,null=True)

    class Meta:
        db_table = u'backup'

class SecurityGroupIngressRule(Base,IngressRule):
    group = models.ForeignKey(SecurityGroup)

    class Meta:
        db_table = u'security_group_ingress_rule'


class FixedIp(Base):
    # address = models.CharField(max_length=255, unique=True)
    address = models.CharField(max_length=255)
    allocated = models.BooleanField(default=False)
    leased = models.BooleanField(default=False)
    host = models.CharField(max_length=255,null=True,blank=True)   #bridge ip，分配给bridge的ip
    network = models.ForeignKey(Network)

    class Meta:
        db_table = u'fixedip'


#class Event(Base):
#    name = models.CharField(max_length=64)
#    start_time = models.DateTimeField()
#    end_time = models.DateTimeField(null=True,blank=True)


class TaskDetail(Base):
    name = models.CharField(max_length=255)
    target = models.CharField(max_length=255)
    type = models.CharField(max_length=255)
    time = models.DateTimeField(auto_now_add=True, blank=True)
    # task_id = models.CharField(max_length=255, unique=True)
    meta = models.ForeignKey(TaskMeta,to_field='task_id')
    uuid = models.CharField(max_length=255,null=True,blank=True)  #唯一值来区分链式任务是否已经创建taskdetail
    class Meta:
        db_table='taskdetail'

    @classmethod
    def create_if_not_exsist(cls,uuid,**kwargs):
        #not cluster call
        if not uuid:
            cls.objects.create(**kwargs)
        else:
            task = cls.objects.first(uuid=uuid)
            if not task:
                return cls.objects.create(uuid=uuid,**kwargs)


class Event(Base):
    #TODO should relate with datacenter
    name = models.CharField(max_length=60)
    desc = models.CharField(max_length=1024,null=True,blank=True)
    reason = models.CharField(max_length=1024)
    status = models.IntegerField()
    start_time = models.DateTimeField(auto_now_add=True, blank=True)
    end_time = models.DateTimeField(blank=True)

    class Meta:
        db_table = u'event'

class Proposal(Base):
    name = models.CharField(max_length=60)
    memory = models.IntegerField() #use KB metric
    disk = models.IntegerField() #use GB metric
    cpu = models.IntegerField()  #core numbers
    network = models.ForeignKey(Network,null=True,blank=True) #network
    storage = models.ForeignKey(Storage,null=True,blank=True)
    interface_type = models.CharField(choices=(('e1000','e1000'),('pcnet','pcnet'),('virtio','virtio'),
                                               ('rtl8139','rtl8139'),('ne2k_pci','ne2k_pci')),default='e1000',max_length=50)
    desc = models.CharField(max_length=1024,null=True,blank=True)

    class Meta:
        db_table = 'proposal'


class Bookmark(Base):
    name = models.CharField(max_length=60)
    url = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)

    class Meta:
        db_table = u'bookmark'
        ordering = ['id']


class IscsiLun(Base):
    target = models.CharField(max_length=255)
    lun = models.CharField(max_length=255)
    path = models.CharField(max_length=255, null=True, blank=True)
    vdisk = models.OneToOneField(VDisk,null=True,blank=True)
    class Meta:
        db_table = 'iscsilun'


class Thinclient(Base):
    name = models.CharField(max_length=255)
    ip = models.CharField(max_length=255)
    mac = models.CharField(max_length=255)
    os = models.CharField(max_length=255)
    cpu = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    mem = models.CharField(max_length=255)
    status = models.CharField(max_length=255)   #是否已连接 0-未连接，1-已连接

    class Meta:
        db_table = 'thinclient'

class CvirtPeriodicTask(models.Model):
    topic = models.ManyToManyField(Server, null=True, blank=True)
    #task level
    level = models.IntegerField(default=10)
    #task description
    name = models.CharField(_(u"name"), max_length=200, unique=True,
                            help_text=_(u"Useful description"))
    task = models.CharField(_(u"task name"), max_length=200)
    interval = models.ForeignKey(IntervalSchedule, null=True, blank=True,
                                 verbose_name=_(u"interval"))
    crontab = models.ForeignKey(CrontabSchedule, null=True, blank=True,
                                verbose_name=_(u"crontab"),
                                help_text=_(u"Use one of interval/crontab"))
    args = models.TextField(_(u"Arguments"),
                            blank=True, default="[]",
                            help_text=_(u"JSON encoded positional arguments"))
    kwargs = models.TextField(_(u"Keyword arguments"),
                              blank=True, default="{}",
                              help_text=_("JSON encoded keyword arguments"))
    queue = models.CharField(_("queue"),
                             max_length=200, blank=True,
                             null=True, default=None,
                             help_text=_(u"Queue defined in CELERY_QUEUES"))
    exchange = models.CharField(_(u"exchange"),
                                max_length=200, blank=True,
                                null=True, default=None)
    routing_key = models.CharField(_(u"routing key"),
                                   max_length=200, blank=True,
                                   null=True, default=None)
    expires = models.DateTimeField(_(u"expires"),
                                   blank=True, null=True)
    enabled = models.BooleanField(_(u"enabled"), default=True)
    last_run_at = models.DateTimeField(
        auto_now=False, auto_now_add=False,
        editable=False, blank=True, null=True)
    total_run_count = models.PositiveIntegerField(default=0, editable=False)
    date_changed = models.DateTimeField(auto_now=True)
    description = models.TextField(_("description"), blank=True)

    objects = CvirtPeriodicTaskManager()
    no_changes = False

    class Meta:
        verbose_name = _(u"periodic task")
        verbose_name_plural = _(u"periodic tasks")
        db_table = 'cvirt_periodic_task'

    def validate_unique(self, *args, **kwargs):
        super(CvirtPeriodicTask, self).validate_unique(*args, **kwargs)
        if not self.interval and not self.crontab:
            raise ValidationError(
                {"interval": ["One of interval or crontab must be set."]})
        if self.interval and self.crontab:
            raise ValidationError(
                {"crontab": ["Only one of interval or crontab must be set"]})

    def save(self, *args, **kwargs):
        self.exchange = self.exchange or None
        self.routing_key = self.routing_key or None
        self.queue = self.queue or None
        if not self.enabled:
            self.last_run_at = None
        super(CvirtPeriodicTask, self).save(*args, **kwargs)

    def __unicode__(self):
        if self.interval:
            return u"%s: %s" % (self.name, unicode(self.interval))
        if self.crontab:
            return u"%s: %s" % (self.name, unicode(self.crontab))
        return u"%s: {no schedule}" % (self.name, )

    @property
    def schedule(self):
        if self.interval:
            return self.interval.schedule
        if self.crontab:
            return self.crontab.schedule


# class ScheduleTestTable(Base):
#     """this table is for testing CvirtDatabaseScheduler"""
#     event = models.CharField(max_length=20)
#
#     class Meta:
#         db_table = 'schedule_test_table'


#注册django admin
from cvirt import settings
if settings.DEBUG:
    import inspect
    from django.contrib import admin
    for k,v in globals().items():
        if v is not Base and inspect.isclass(v) and issubclass(v,Base):
            admin.site.register(v)
